package biolabs.model.vis.j2d;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import biolabs.model.LiquidEnvironment2D;
import biolabs.space.Continuous2DPosition;
import biolabs.space.Discrete2DPosition;
import biolabs.space.Generic2DGrid;
import biolabs.space.Grid;
import biolabs.visual.Visualizer;
import biolabs.visual.j2d.Java2DPainter;

public class LiqEnv2DVisualizer implements
		Visualizer<LiquidEnvironment2D, Java2DPainter> {

	private static final Color[] COLORS = new Color[] {
		Color.CYAN,
		Color.MAGENTA,
		Color.YELLOW,
		Color.PINK,
		Color.GREEN,
		Color.ORANGE,
		Color.GRAY,
		Color.RED,
		Color.BLUE,
		Color.LIGHT_GRAY,
		Color.DARK_GRAY,
	};

	private final double maxConc = 200;
	private int nextColor = 0;
	private final Map<Object, Color> substanceColors = new HashMap<Object, Color>();

	@Override
	public Java2DPainter visualize(LiquidEnvironment2D env) {

		final Discrete2DPosition d = env.getDimensions();
		final Rectangle shape = new Rectangle(d.getX(), d.getY());

		Object[] substances = new Object[env.getSubstances().size()];
		env.getSubstances().toArray(substances);
		float[][] cmyComponents = new float[substances.length][3];
		ArrayList<Grid<Double, Discrete2DPosition, Continuous2DPosition>> concGrids =
			new ArrayList<Grid<Double, Discrete2DPosition, Continuous2DPosition>>(substances.length);
		float[] rgbComps = new float[3];
		for(int i=0; i<substances.length; ++i) {
			getColorOf(substances[i]).getRGBColorComponents(rgbComps);
			for(int j=0; j<3; ++j)
				cmyComponents[i][j] = 1-rgbComps[j];
			concGrids.add(env.getConcentration(substances[i]));
		}
		final Generic2DGrid<Color> colorGrid = new Generic2DGrid<Color>(d);
		for(int y=0; y<d.getY(); ++y) {
			for(int x=0; x<d.getX(); ++x) {
				Discrete2DPosition pos = new Discrete2DPosition(x, y);
				if(env.getChildAt(pos) == null) {
					float cyan=0, magenta=0, yellow=0;
					for(int i=0; i<substances.length; ++i) {
						double c = Math.min(concGrids.get(i).at(pos), maxConc);
						double w = c/maxConc;
						cyan += w * cmyComponents[i][0];
						magenta += w * cmyComponents[i][1];
						yellow += w * cmyComponents[i][2];
					}
					Color col = new Color(1-Math.min(cyan, 1), 1-Math.min(magenta, 1), 1-Math.min(yellow, 1), 0.5f);
					colorGrid.setField(x, y, col);
				}
			}
		}

		return new Java2DPainter() {
			@Override
			public void paint(Graphics2D graphics) {

				Rectangle clip = graphics.getClipBounds();

				// clear the clip
				graphics.clearRect(clip.x, clip.y, clip.width, clip.height);

				// draw the environment bounds
				graphics.draw(shape);

				// draw concentrations
				Color savedFill = graphics.getColor();
				int miny = Math.max(clip.y, 0);
				int maxy = Math.min(clip.y + clip.height, d.getY());
				int minx = Math.max(clip.x, 0);
				int maxx = Math.min(clip.x + clip.width, d.getX());
				for(int y=miny; y<maxy; ++y) {
					for(int x=minx; x<maxx; ++x) {
						Color c = colorGrid.at(x, y);
						if(c != null) {
							graphics.setColor(c);
							graphics.fillRect(x, y, 1, 1);
						}
					}
				}
				graphics.setColor(savedFill);
			}

			@Override
			public Rectangle getBounds() {
				return shape;
			}
		};
	}

	private synchronized Color getColorOf(Object sub) {
		Color c = substanceColors.get(sub);
		if(c == null) {
			c = COLORS[nextColor++];
			substanceColors.put(sub, c);
		}
		return c;
	}

}
